package productions;

import exceptions.ParserException;
import lexico.ErrorTable;
import lexico.SymbolTable;
import lexico.TokenClass;

/**
 * @author heekinho
 */
public class StartProduction extends AbstractProductionRule {
    /* Muitos dos métodos irão precisar de algo assim: */

    private static StartProduction instance = new StartProduction();

    public static StartProduction getInstance() {
        return instance;
    }

    /**
     * Regra: start : algoritmo declarations principal (funcao | variaveis ';')* EOF;
     * @return
     * @throws ParserException
     */
    @Override
    public boolean analyze(SymbolTable st, ErrorTable et) throws ParserException {
        if (!AlgoritmoProduction.getInstance().analyze(st, et)) {
            return skipUntilSynchronize(st, et, "Era esperado a palavra reservada 'algoritmo'.");
        }

        if (!DeclarationsProduction.getInstance().analyze(st, et)) {
            return skipUntilSynchronize(st, et, "Erro no bloco de declarações.");
        }
        if (!PrincipalProduction.getInstance().analyze(st, et)) {
            return skipUntilSynchronize(st, et, "Erro na declaração da função principal.");
        }


        while (!st.eof() && first.contains(st.getCurrent().getTokenClass())) {
            if (FuncaoProduction.getInstance().analyze(st, et)) {
                continue;
            }

            if (VariaveisProduction.getInstance().analyze(st, et)) {
                if (!basicParse(st, TokenClass.DELIMITER_SEMICOLON)) {
                    return skipUntilSynchronize(st, et, "Era esperado um ';'.");
                }
                continue;
            }

            return skipUntilSynchronize(st, et, "Erro na estrutura do programa. Era esperado função ou declaração de variável.");
        }

        if (st.eof()) {
            return true;
        }

        et.addError(st, "Erro na estrutura do programa. Era esperado fim de arquivo.");
        return false;
    }

    @Override
    protected void populateFirst() {
        first.add(TokenClass.KEYWORD_FUNCAO);
        first.add(TokenClass.KEYWORD_VARIAVEIS);
    }

    @Override
    protected void populateFollow() {
        follow.add(TokenClass.KEYWORD_ALGORITMO);
    }

    
}
